package com.bootdo.hjh.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import org.apache.commons.collections.CollectionUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bootdo.common.service.DistConfigValueService;
import com.bootdo.common.utils.DaYuSms;
import com.bootdo.common.utils.DateUtils;
import com.bootdo.common.utils.PointTradeType;
import com.bootdo.common.utils.StringUtils;
import com.bootdo.hjh.cache.MemberCache;
import com.bootdo.hjh.cache.Node;
import com.bootdo.hjh.cache.NodeInfo;
import com.bootdo.hjh.cache.NodeVO;
import com.bootdo.hjh.cache.ProductCache;
import com.bootdo.hjh.dao.CashPointsDOMapper;
import com.bootdo.hjh.dao.OrderDOMapper;
import com.bootdo.hjh.dao.PointsMapper;
import com.bootdo.hjh.dao.ProductPointsDOMapper;
import com.bootdo.hjh.domain.BankCard;
import com.bootdo.hjh.domain.BonusFlag;
import com.bootdo.hjh.domain.CashPointsDO;
import com.bootdo.hjh.domain.CashPointsDOExample;
import com.bootdo.hjh.domain.OrderDO;
import com.bootdo.hjh.domain.ProductPointsDO;
import com.bootdo.hjh.domain.ProductPointsDOExample;
import com.bootdo.hjh.domain.ProductType;
import com.bootdo.hjh.domain.StockDO;
import com.bootdo.hjh.domain.Withdraw;
import com.bootdo.hjh.ex.ThrowUtils;
import com.bootdo.hjh.service.BankCardService;
import com.bootdo.hjh.service.PointsService;
import com.bootdo.hjh.service.StockService;
import com.bootdo.hjh.vo.GroupInfo;
import com.bootdo.oa.domain.NotifyDO;
import com.bootdo.oa.domain.NotifyType;
import com.bootdo.oa.service.NotifyRecordService;
import com.bootdo.oa.service.NotifyService;
import com.bootdo.shop.service.ShopOrderService;
import com.bootdo.system.dao.UserDao;
import com.bootdo.system.domain.UserDO;
import com.bootdo.system.service.UserService;

@Service
@Transactional
public class PointsServiceImpl implements PointsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PointsServiceImpl.class);

    // 补货订单前缀
    private static final String BUHUO_PREFIX = "B";

    private static final String OLD_MEMBER_TO_PROXY_PREFIX = "C";

    private static final String NEW_MEMBER_TO_PROXY_PREFIX = "D";

    @Autowired
    private PointsMapper pointsMapper;
    @Autowired
    private BankCardService bankCardService;

    @Autowired
    private ProductPointsDOMapper productPointsDOMapper;

    @Autowired
    private CashPointsDOMapper cashPointsDOMapper;

    @Autowired
    OrderDOMapper orderDOMapper;

    @Autowired
    UserDao userDao;

    @Autowired
    DaYuSms daYuSms;

    @Autowired
    ProductCache productCache;

    @Autowired
    MemberCache memberCache;

    @Autowired
    UserService userService;

    @Autowired
    StockService stockService;

    @Autowired
    DistConfigValueService distConfigValueService;

    @Autowired
    private ShopOrderService shopOrderService;

    @Autowired
    NotifyRecordService notifyRecordService;

    @Autowired
    NotifyService notifyService;

    @Override
    public Integer cashPointsTotal(Long userId) {

        Integer total = pointsMapper.cashPointsTotal(userId);
        return total == null ? 0 : total;
    }

    @Override
    public Integer productPointsTotal(Long userId) {
        Integer total = pointsMapper.productPointsTotal(userId);
        return total == null ? 0 : total;
    }

    @Override
    public Integer withdraw(Withdraw withdraw) {
        BankCard bankCard = bankCardService.get(withdraw.getCardId());
        withdraw.setBankName(bankCard.getBankName());
        withdraw.setCardNumber(bankCard.getCardNumber());
        withdraw.setCardUserName(bankCard.getCardUserName());
        withdraw.setAmount(withdraw.getAmount() * 100);
        //手续费
        Float serviceCharge = withdraw.getAmount() * 0.05f;
        withdraw.setServiceCharge(serviceCharge.intValue());
        withdraw.setExchangeAmount(withdraw.getAmount() - withdraw.getServiceCharge());
        //添加明细
        CashPointsDO firstCashPointsDO = new CashPointsDO();
        Integer cashAmount = withdraw.getAmount();
        firstCashPointsDO.setAmount(-cashAmount.intValue());
        firstCashPointsDO.setCreateTime(new Date());
        firstCashPointsDO.setLastModifyTime(new Date());
        firstCashPointsDO.setType(PointTradeType.WITHDRAWAL); //TODO 类型
        firstCashPointsDO.setRemark("提现");
        firstCashPointsDO.setServiceCharge(serviceCharge.intValue());//TODO 手续费,只有提现的时候有手续费
        firstCashPointsDO.setUserId(withdraw.getUserId());
        cashPointsDOMapper.insertSelective(firstCashPointsDO);
        int m = pointsMapper.addWithdraw(withdraw);
        if (m > 0) {
            daYuSms.sendWithdrawNotice(withdraw.getUserId(), withdraw.getAmount());
        }
        return 1;
    }

    // 可重复进入
    @Override
    @Transactional
    public Integer splitPointAfterOrderSuccess(Integer orderId) {
        LOGGER.info("为订单（orderId=" + orderId + "）分配积分");
        //查询订单
        OrderDO orderDO = orderDOMapper.selectByPrimaryKey(orderId);

        int quality = orderDO.getQuantity();

        ThrowUtils.throwCondition(orderDO == null, 110, "积分分账失败，(orderId=" + orderId + ")订单不存在");

        //判断订单状态是否已经支付
        ThrowUtils.throwCondition(orderDO.getOrderStatus() < 1, 111, "积分分账失败，(orderId=" + orderId + ")订单尚未支付，不能分账");

        String orderNo = orderDO.getOrderNo();
        String title = "新人注册";
        boolean setProxy = false;
        if (StringUtils.startsWith(orderNo, BUHUO_PREFIX)) {
            title = "会员补货";
        } else if (StringUtils.startsWith(orderNo, OLD_MEMBER_TO_PROXY_PREFIX)) {
            title = "老会员升级代理";
            setProxy = true;
        } else if (StringUtils.startsWith(orderNo, NEW_MEMBER_TO_PROXY_PREFIX)) {
            title = "新会员升级代理";
            setProxy = true;
        } else {
            title = "新人注册";
        }

        Integer productType = ProductType.DU_XIAO_LI.getValue();
        if (orderDO.getProductId().equals(ProductType.HEI_MEI.getProductId())) {
            productType = ProductType.HEI_MEI.getValue();
        }

        // 新人是否激活，是否添加库存标志
        boolean isFr = orderDO.getIsFr() != null && orderDO.getIsFr() > 0;
        Long userId = orderDO.getUserId();
        if (!isFr) {
            // 创建的新用户ID
            UserDO me = userDao.get(userId);
            if (me.getActiveTime() == null) {
                me.setActiveTime(DateTime.now().toDate());
                userService.update(me);
            }
            if (setProxy && (me.getAgentLevel()==null || me.getAgentLevel() <= 0)) {
                me.setAgentLevel(1);
                userService.update(me);

                // TODO 触发绩点计算，升级计算
                userService.upgradeTrigger(me.getUserId());
            }
            {
                // 计算库存余额
                Integer stockBalance = stockService.myStockBalance(userId, productType);
                stockBalance = stockBalance + quality;

                StockDO stockDO = new StockDO();
                stockDO.setAmount(quality);
                stockDO.setBalance(stockBalance);
                stockDO.setCreateTime(new Date());
                stockDO.setLastModifyTime(new Date());
                stockDO.setProductType(productType);
                stockDO.setUserId(userId);
                stockDO.setRemark(title + "新增库存数量：" + quality);
                stockService.save(stockDO);

                LOGGER.info("更新用户({})的激活时间,添加库存，当前库存为:({})", me.getUsername(), stockBalance);
                //更新缓存
                memberCache.reloadNodeFromDB(me.getUserId());

                LOGGER.info("更新缓存之后的对象信息：{}", memberCache.getNodeInfo(me.getStartUserId(), me.getUserId()));
            }
            orderDOMapper.updateFrStatus(1, orderId);

            // 检查自己的订单是否有未分润的
            Integer stockBalance = stockService.myStockBalance(userId, productType);
            if (stockBalance >= 0) {
                List<OrderDO> nonFrOrders = orderDOMapper.getNonFrOrder(userId, orderDO.getProductId());
                if (!CollectionUtils.isEmpty(nonFrOrders)) {
                    for (OrderDO nonFrOrder : nonFrOrders) {
                        int cashTotalAmount = nonFrOrder.getAmount();
                        String newOrderNo = orderDO.getOrderNo();
                        String newTitle = "新人注册";
                        Integer cashPointType = 3;
                        // 通知相关
                        NotifyType notifyType = null;
                        String content = "";
                        if (StringUtils.startsWith(newOrderNo, BUHUO_PREFIX)) {
                            newTitle = "会员补货";
                            cashPointType = PointTradeType.BUHUO_ORDER_POINT;

                            notifyType = NotifyType.BUHUO_ORDER_FR_SUCCESS;

                            content = "补货成功， 恭喜您获得" +cashTotalAmount/100.0+"(元)积分";

                        } else if (StringUtils.startsWith(newOrderNo, OLD_MEMBER_TO_PROXY_PREFIX)) {
                            newTitle = "老会员升级代理";
                            cashPointType = PointTradeType.OLD_MEMBER_NEW_PROXY_RECOMMENDED_AWARD;
                            cashTotalAmount = (int) distConfigValueService.getOLD_MEMBER_TO_PROXY_RECOMMENDED_AWARD();
                            content = "会员升级代理成功， 恭喜您获得" +cashTotalAmount/100.0+"(元)积分推荐奖奖励";

                            notifyType = NotifyType.PROXY_FR_SUCCESS;
                        } else if (StringUtils.startsWith(newOrderNo, NEW_MEMBER_TO_PROXY_PREFIX)) {
                            newTitle = "新会员升级代理";
                            cashPointType = PointTradeType.NEW_MEMBER_NEW_PROXY_RECOMMENDED_AWARD;

                            cashTotalAmount = (int) distConfigValueService.getNEW_MEMBER_TO_PROXY_RECOMMENDED_AWARD();
                            content = "会员升级代理成功， 恭喜您获得" +cashTotalAmount/100.0+"(元)积分推荐奖奖励";
                            notifyType = NotifyType.PROXY_FR_SUCCESS;
                        } else {
                            newTitle = "新人注册";
                            cashPointType = PointTradeType.NEW_MEMBER_ORDER;

                            notifyType = NotifyType.MEMBER_ORDER_FR_SUCCESS;
                            content = "注册会员成功， 恭喜您获得" +cashTotalAmount/100.0+"(元)积分";
                        }
                        CashPointsDO newMemberCashPoints = new CashPointsDO();

                        newMemberCashPoints.setAmount(cashTotalAmount);
                        newMemberCashPoints.setCreateTime(new Date());
                        newMemberCashPoints.setLastModifyTime(new Date());
                        newMemberCashPoints.setType(cashPointType); //类型
                        newMemberCashPoints.setRemark(newTitle + "新增分润积分");
                        newMemberCashPoints.setServiceCharge(0);//手续费,只有提现的时候有手续费
                        newMemberCashPoints.setUserId(userId);
                        cashPointsDOMapper.insertSelective(newMemberCashPoints);
                        notifyService.saveNotify(notifyType, content, userId);
                        orderDOMapper.updateFrUserGain(2, nonFrOrder.getId());
                    }
                }
            }
        }

        boolean isFrUserGain = orderDO.getFrUserGain() != null && orderDO.getFrUserGain() > 0;
        Long frUserId = orderDO.getFrUserId();
        if (!isFrUserGain && frUserId != null && frUserId > 0) {
            // 获取分润人
            UserDO frUser = userDao.get(frUserId);
            if (StringUtils.startsWith(orderNo, BUHUO_PREFIX)) {
                // 修改发货时间，为定时任务记录订单驻留时间
                orderDOMapper.updateBuhuoDeliverClearTime(orderId);

                // 通知父亲发货
                String content = "为避免造成损失，请您尽快发货，订单编号：" + orderNo;
                notifyService.saveNotify(NotifyType.DELIVER, content, frUserId);

            } else if (StringUtils.startsWith(orderNo, OLD_MEMBER_TO_PROXY_PREFIX)) {

                // 获取公司用户
                long companyAccountUserId = distConfigValueService.getCOMPANY_ACCOUNT_USER_ID();
                // 获取公司库存
                int companyAccountStockBalance =
                        stockService.myStockBalance(companyAccountUserId, productType);
                companyAccountStockBalance = companyAccountStockBalance - quality;

                // 公司出货
                StockDO stockDO = new StockDO();
                stockDO.setAmount(-quality);
                stockDO.setBalance(companyAccountStockBalance);
                stockDO.setCreateTime(new Date());
                stockDO.setLastModifyTime(new Date());
                stockDO.setProductType(productType);
                stockDO.setUserId(companyAccountUserId);
                stockDO.setRemark(title + "扣减公司库存数量：" + quality);
                stockService.save(stockDO);

                // 奖励推荐人
                long oldMemberToProxyRecommendedAward =
                        distConfigValueService.getOLD_MEMBER_TO_PROXY_RECOMMENDED_AWARD();
                if (oldMemberToProxyRecommendedAward > 0) {
                    CashPointsDO recommendedAward = new CashPointsDO();
                    recommendedAward.setAmount((int) oldMemberToProxyRecommendedAward);
                    recommendedAward.setCreateTime(new Date());
                    recommendedAward.setLastModifyTime(new Date());
                    recommendedAward.setType(PointTradeType.OLD_MEMBER_NEW_PROXY_RECOMMENDED_AWARD); //类型
                    recommendedAward.setRemark(title + "推荐奖积分");
                    recommendedAward.setServiceCharge(0);//手续费,只有提现的时候有手续费
                    recommendedAward.setUserId(frUserId);
                    cashPointsDOMapper.insertSelective(recommendedAward);

                    String content = "会员升级代理成功， 恭喜您获得" +oldMemberToProxyRecommendedAward/100.0+"(元)积分推荐奖奖励";
                    NotifyType notifyType = NotifyType.PROXY_FR_SUCCESS;
                    notifyService.saveNotify(notifyType, content, userId);
                }
                orderDOMapper.updateFrUserGain(2, orderId);

            } else if (StringUtils.startsWith(orderNo, NEW_MEMBER_TO_PROXY_PREFIX)) {
                // 新会员升级代理
                // 获取公司用户
                long companyAccountUserId = distConfigValueService.getCOMPANY_ACCOUNT_USER_ID();
                // 获取公司库存
                int companyAccountStockBalance =
                        stockService.myStockBalance(companyAccountUserId, productType);
                companyAccountStockBalance = companyAccountStockBalance - quality;

                // 公司出货
                StockDO stockDO = new StockDO();
                stockDO.setAmount(-quality);
                stockDO.setBalance(companyAccountStockBalance);
                stockDO.setCreateTime(new Date());
                stockDO.setLastModifyTime(new Date());
                stockDO.setProductType(productType);
                stockDO.setUserId(companyAccountUserId);
                stockDO.setRemark(title + "扣减公司库存数量：" + quality);
                stockService.save(stockDO);

                // 奖励推荐人
                long newMemberToProxyRecommendedAward =
                        distConfigValueService.getNEW_MEMBER_TO_PROXY_RECOMMENDED_AWARD();
                if (newMemberToProxyRecommendedAward > 0) {
                    CashPointsDO recommendedAward = new CashPointsDO();
                    recommendedAward.setAmount((int) newMemberToProxyRecommendedAward);
                    recommendedAward.setCreateTime(new Date());
                    recommendedAward.setLastModifyTime(new Date());
                    recommendedAward.setType(PointTradeType.NEW_MEMBER_NEW_PROXY_RECOMMENDED_AWARD); //类型
                    recommendedAward.setRemark(title + "荐奖积分");
                    recommendedAward.setServiceCharge(0);//手续费,只有提现的时候有手续费
                    recommendedAward.setUserId(frUserId);
                    cashPointsDOMapper.insertSelective(recommendedAward);

                    String content = "会员升级代理成功， 恭喜您获得" +newMemberToProxyRecommendedAward/100.0+"(元)积分推荐奖奖励";
                    NotifyType notifyType = NotifyType.PROXY_FR_SUCCESS;
                    notifyService.saveNotify(notifyType, content, frUserId);
                }
                orderDOMapper.updateFrUserGain(2, orderId);
            } else {
                // 注册会员订单
                // 直接扣减分润人库存

                Integer stockBalance = stockService.myStockBalance(frUserId, productType);
                stockBalance = stockBalance - quality;
                StockDO stockDO = new StockDO();
                stockDO.setAmount(-quality);
                stockDO.setBalance(stockBalance);
                stockDO.setCreateTime(new Date());
                stockDO.setLastModifyTime(new Date());
                stockDO.setProductType(productType);
                stockDO.setUserId(frUserId);
                stockDO.setRemark(title + "扣减上级库存数量：" + quality);
                stockService.save(stockDO);

                // 新增现金积分
                if (stockBalance >= 0) {
                    // 如果库存充足则添加直接新增积分
                    CashPointsDO newMemberCashPoints = new CashPointsDO();
                    int cashTotalAmount = orderDO.getAmount();
                    newMemberCashPoints.setAmount(cashTotalAmount);
                    newMemberCashPoints.setCreateTime(new Date());
                    newMemberCashPoints.setLastModifyTime(new Date());
                    newMemberCashPoints.setType(PointTradeType.NEW_MEMBER_ORDER); //类型
                    newMemberCashPoints.setRemark(title + "新增分润积分");
                    newMemberCashPoints.setServiceCharge(0);//手续费,只有提现的时候有手续费
                    newMemberCashPoints.setUserId(frUserId);
                    cashPointsDOMapper.insertSelective(newMemberCashPoints);
                    orderDOMapper.updateFrUserGain(2, orderId);
                    String content = "会员升级代理成功， 恭喜您获得" +cashTotalAmount/100.0+"(元)积分推荐奖奖励";
                    NotifyType notifyType = NotifyType.PROXY_FR_SUCCESS;
                    notifyService.saveNotify(notifyType, content, frUserId);
                } else {
                    orderDOMapper.updateFrUserGain(1, orderId);
                    notifyService.saveNotify(NotifyType.STOCK_LOW, "您的库存不足，请尽快补货，避免造成不必要损失", frUserId);
                }
            }
        }
        return 1;
    }

    /**
     * 上级代理发货
     */
    public void deliver(Integer orderId) {
        OrderDO orderDO = orderDOMapper.selectByPrimaryKey(orderId);
        Long superiorId = orderDO.getFrUserId();
        int quality = orderDO.getQuantity();

        ThrowUtils.throwCondition(orderDO == null, 110, "积分分账失败，(orderId=" + orderId + ")订单不存在");

        //判断订单状态是否已经支付
        ThrowUtils.throwCondition(orderDO.getOrderStatus() < 1, 111, "发货失败，(orderId=" + orderId + ")订单尚未支付，不能发货");

        String orderNo = orderDO.getOrderNo();

        ThrowUtils.throwCondition(!StringUtils.startsWith(orderNo, BUHUO_PREFIX), 111, "发货失败，(orderId=" + orderId +
                ")非补货订单，不能发货");

        // 扣减库存
        Integer stockBalance = stockService.myStockBalance(superiorId, ProductType.DU_XIAO_LI.getValue());
        stockBalance = stockBalance - quality;
        StockDO stockDO = new StockDO();
        stockDO.setAmount(-quality);
        stockDO.setBalance(stockBalance);
        stockDO.setCreateTime(new Date());
        stockDO.setLastModifyTime(new Date());
        stockDO.setProductType(ProductType.DU_XIAO_LI.getValue());
        stockDO.setUserId(superiorId);
        stockDO.setRemark("补货订单发货扣减上级库存数量：" + quality);
        stockService.save(stockDO);

        // 新增现金积分
        if (stockBalance >= 0) {
            // 如果库存充足则添加直接新增积分
            CashPointsDO newMemberCashPoints = new CashPointsDO();
            int cashTotalAmount = orderDO.getAmount();
            newMemberCashPoints.setAmount(cashTotalAmount);
            newMemberCashPoints.setCreateTime(new Date());
            newMemberCashPoints.setLastModifyTime(new Date());
            newMemberCashPoints.setType(PointTradeType.BUHUO_ORDER_POINT); //类型
            newMemberCashPoints.setRemark("补货订单发货新增分润积分");
            newMemberCashPoints.setServiceCharge(0);//手续费,只有提现的时候有手续费
            newMemberCashPoints.setUserId(superiorId);
            cashPointsDOMapper.insertSelective(newMemberCashPoints);
            orderDOMapper.updateFrUserGain(2, orderId);

            notifyService.saveNotify(NotifyType.BUHUO_ORDER_FR_SUCCESS, "补货成功， 恭喜您获得" +cashTotalAmount/100.0+"(元)积分", superiorId);
        } else {
            orderDOMapper.updateFrUserGain(1, orderId);
            notifyService.saveNotify(NotifyType.STOCK_LOW, "您的库存不足，请尽快补货，避免造成不必要损失", superiorId);
        }
    }

    /**
     * 定时任务更新补货单驻留超时的分润人
     */
    @Override
    public void orderRetain() {
        // 查询驻留订单
        List<OrderDO> buhuoOrder = orderDOMapper.getBuhuoOrder();
        if (!CollectionUtils.isEmpty(buhuoOrder)) {
            long stillTime = distConfigValueService.getBUHUO_ORDER_STILL_TIME();
            for (OrderDO orderDO : buhuoOrder) {
                Date deliverClearTime = orderDO.getShippingTime();
                long dt = deliverClearTime.getTime();
                if (dt + stillTime * 3600000L < System.currentTimeMillis()) {
                    // 过期了，更换分润人
                    Long newFrUserId = memberCache.superiorUserId(orderDO.getFrUserId());
                    if (newFrUserId == null) {
                        newFrUserId = distConfigValueService.getCOMPANY_ACCOUNT_USER_ID();
                    }
                    orderDOMapper.updateBuhuoDeliverClearTimeAndFrUser(orderDO.getId(), newFrUserId);
                }
            }
        }
    }

    /**
     * 商城订单分润
     *
     * @param userId
     * @param firstRecommendUserId
     * @param secondRecommendUserId
     * @param amount
     */
    public void shopOrdersplit(Long userId, Long firstRecommendUserId, Long secondRecommendUserId, Integer amount) {
        Node userNode = memberCache.getNodeInCache(userId);
        if (null == userNode) {
            return;
        }
        if (userNode.getInfo().getAgentLevel() != null && userNode.getInfo().getAgentLevel() > 1) {
            return;
        }
        //计算比例
        if (firstRecommendUserId != null) {

            //分配第一层现金积分
            CashPointsDO firstCashPointsDO = new CashPointsDO();
            Double cashTotalAmount = amount * 0.25;
            Double cashAmount = cashTotalAmount * 0.6;
            firstCashPointsDO.setAmount(cashAmount.intValue());
            firstCashPointsDO.setCreateTime(new Date());
            firstCashPointsDO.setLastModifyTime(new Date());
            firstCashPointsDO.setType(PointTradeType.SHARE_OUT_BONUS); //TODO 类型
            firstCashPointsDO.setRemark("商城订单分润");
            firstCashPointsDO.setServiceCharge(0);//TODO 手续费,只有提现的时候有手续费
            firstCashPointsDO.setUserId(firstRecommendUserId);
            cashPointsDOMapper.insertSelective(firstCashPointsDO);

            //分配第一层商品积分
            ProductPointsDO firstProductPointsDO = new ProductPointsDO();
            Double productTotalAmount = amount * 0.25;
            Double productAmount = productTotalAmount * 0.4;
            firstProductPointsDO.setAmount(productAmount.intValue());
            firstProductPointsDO.setCreateTime(new Date());
            firstProductPointsDO.setLastModifyTime(new Date());
            firstProductPointsDO.setType(PointTradeType.SHARE_OUT_BONUS); //TODO 类型
            firstProductPointsDO.setRemark("商城订单分润");
            firstProductPointsDO.setUserId(firstRecommendUserId);
            productPointsDOMapper.insertSelective(firstProductPointsDO);
        }
        if (secondRecommendUserId != null) {
            //分配第二层现金积分
            CashPointsDO secondCashPointsDO = new CashPointsDO();
            Double cashTotalAmount = amount * 0.1;
            Double cashAmount = cashTotalAmount * 0.6;
            secondCashPointsDO.setAmount(cashAmount.intValue());
            secondCashPointsDO.setCreateTime(new Date());
            secondCashPointsDO.setLastModifyTime(new Date());
            secondCashPointsDO.setType(PointTradeType.SHARE_OUT_BONUS); //TODO 类型
            secondCashPointsDO.setRemark("商城订单分润");
            secondCashPointsDO.setServiceCharge(0);//TODO 手续费,只有提现的时候有手续费
            secondCashPointsDO.setUserId(secondRecommendUserId);
            cashPointsDOMapper.insertSelective(secondCashPointsDO);

            //分配第二层商品积分
            ProductPointsDO secondProductPointsDO = new ProductPointsDO();
            Double productTotalAmount = amount * 0.1;
            Double productAmount = productTotalAmount * 0.4;
            secondProductPointsDO.setAmount(productAmount.intValue());
            secondProductPointsDO.setCreateTime(new Date());
            secondProductPointsDO.setLastModifyTime(new Date());
            secondProductPointsDO.setType(PointTradeType.SHARE_OUT_BONUS); //TODO 类型
            secondProductPointsDO.setRemark("商城订单分润");
            secondProductPointsDO.setUserId(secondRecommendUserId);
            productPointsDOMapper.insertSelective(secondProductPointsDO);

        }
    }

    @Override
    public List<CashPointsDO> listCashPoints(Long userId, Integer type, Date beginDate, Date endDate, Integer offset,
                                             Integer limit) {
        CashPointsDOExample example = new CashPointsDOExample();
        CashPointsDOExample.Criteria criteria = example.createCriteria();
        if (null != userId) {
            criteria.andUserIdEqualTo(userId);
        }
        if (beginDate != null) {
            criteria.andCreateTimeGreaterThanOrEqualTo(beginDate);
        }
        if (endDate != null) {
            //结束时间+1天
            LocalDate endLocalDate =
                    LocalDateTime.ofInstant(endDate.toInstant(), ZoneOffset.systemDefault()).plusDays(1l).toLocalDate();

            endDate = Date.from(endLocalDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());

            criteria.andCreateTimeLessThan(endDate);

        }
        if (type != null) {
            if (type > 0) {
                criteria.andTypeEqualTo(type);
            } else if (type == -1) {
                criteria.andTypeGreaterThan(3);
            }
        }
        example.setOffset(offset);
        example.setLimit(limit);
        example.setOrderByClause(" id desc ");
        List<CashPointsDO> list = cashPointsDOMapper.selectByExample(example);
        for (CashPointsDO cpd : list) {
            if (cpd.getReciprocalUserId() != null) {
                NodeInfo nodeInfo = memberCache.getNodeInfo(cpd.getReciprocalUserId());
                if (null != nodeInfo) {
                    cpd.setReciprocalName(nodeInfo.getUsername());
                }
            }
        }
        return list;
    }

    @Override
    public int countCashPoint(Long userId, Integer type, Date beginDate, Date endDate) {
        CashPointsDOExample example = new CashPointsDOExample();
        CashPointsDOExample.Criteria criteria = example.createCriteria();
        if (null != userId) {
            criteria.andUserIdEqualTo(userId);
        }
        if (beginDate != null) {
            criteria.andCreateTimeGreaterThanOrEqualTo(beginDate);
        }
        if (endDate != null) {
            //结束时间+1天
            LocalDate endLocalDate =
                    LocalDateTime.ofInstant(endDate.toInstant(), ZoneOffset.systemDefault()).plusDays(1l).toLocalDate();

            endDate = Date.from(endLocalDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());

            criteria.andCreateTimeLessThan(endDate);

        }
        if (type != null) {
            if (type > 0) {
                criteria.andTypeEqualTo(type);
            } else if (type == -1) {
                criteria.andTypeGreaterThan(3);
            }
        }
        int countByExample = cashPointsDOMapper.countByExample(example);
        return countByExample;
    }

    @Override
    public List<ProductPointsDO> listProductPoints(Long userId, Integer type, Date beginDate, Date endDate,
                                                   Integer offset, Integer
                                                           limit) {
        ProductPointsDOExample example = new ProductPointsDOExample();
        ProductPointsDOExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        if (beginDate != null) {
            criteria.andCreateTimeGreaterThanOrEqualTo(beginDate);
        }
        if (endDate != null) {
            //结束时间+1天
            LocalDate endLocalDate =
                    LocalDateTime.ofInstant(endDate.toInstant(), ZoneOffset.systemDefault()).plusDays(1l).toLocalDate();

            endDate = Date.from(endLocalDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());

            criteria.andCreateTimeLessThan(endDate);

        }
        if (type != null && type > 0) {
            criteria.andTypeEqualTo(type);
        }
        example.setOffset(offset);
        example.setLimit(limit);
        example.setOrderByClause(" id desc ");
        List<ProductPointsDO> list = productPointsDOMapper.selectByExample(example);
        for (ProductPointsDO cpd : list) {
            if (cpd.getReciprocalUserId() != null) {
                NodeInfo nodeInfo = memberCache.getNodeInfo(cpd.getReciprocalUserId());
                if (null != nodeInfo) {
                    cpd.setReciprocalName(nodeInfo.getUsername());
                }
            }
        }
        return list;
    }

    @Override
    public int countProductPoint(Long userId, Integer type, Date beginDate, Date endDate) {
        ProductPointsDOExample example = new ProductPointsDOExample();
        ProductPointsDOExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        if (beginDate != null) {
            criteria.andCreateTimeGreaterThanOrEqualTo(beginDate);
        }
        if (endDate != null) {
            //结束时间+1天
            LocalDate endLocalDate =
                    LocalDateTime.ofInstant(endDate.toInstant(), ZoneOffset.systemDefault()).plusDays(1l).toLocalDate();

            endDate = Date.from(endLocalDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());

            criteria.andCreateTimeLessThan(endDate);

        }
        if (type != null && type > 0) {
            criteria.andTypeEqualTo(type);
        }
        int countByExample = productPointsDOMapper.countByExample(example);
        return countByExample;
    }

    @Override
    @Transactional
    public int cashPointTransfer(Long fromUserId, String fromUsername, String toUsername, String toRealname,
                                 Integer amount) {
        amount = amount * 100;

        UserDO toUser = userDao.getByUsername(toUsername);
        ThrowUtils.throwCondition(toUser == null, 101, "转入用户不存在");
        ThrowUtils.throwCondition(!StringUtils.equals(toRealname, toUser.getName()), 102, "转入用户真实名错误");
        Integer cashPointsTotal = this.cashPointsTotal(fromUserId);
        ThrowUtils.throwCondition(cashPointsTotal < amount, 103, "现金积分不足");

        //扣
        CashPointsDO firstCashPointsDO = new CashPointsDO();
        firstCashPointsDO.setAmount(-amount);
        firstCashPointsDO.setCreateTime(new Date());
        firstCashPointsDO.setLastModifyTime(new Date());
        firstCashPointsDO.setType(PointTradeType.TRANSFER); //TODO 类型
        firstCashPointsDO.setRemark("转出-去向用户【" + toRealname + "】");
        firstCashPointsDO.setServiceCharge(0);//TODO 手续费,只有提现的时候有手续费
        firstCashPointsDO.setUserId(fromUserId);
        firstCashPointsDO.setReciprocalUserId(toUser.getUserId());
        cashPointsDOMapper.insertSelective(firstCashPointsDO);

        //收
        CashPointsDO secondCashPointsDO = new CashPointsDO();
        secondCashPointsDO.setAmount(amount);
        secondCashPointsDO.setCreateTime(new Date());
        secondCashPointsDO.setLastModifyTime(new Date());
        secondCashPointsDO.setType(PointTradeType.TRANSFER); //TODO 类型
        secondCashPointsDO.setRemark("转入-来源用户【" + fromUsername + "】");
        secondCashPointsDO.setServiceCharge(0);//TODO 手续费,只有提现的时候有手续费
        secondCashPointsDO.setUserId(toUser.getUserId());
        secondCashPointsDO.setReciprocalUserId(fromUserId);
        cashPointsDOMapper.insertSelective(secondCashPointsDO);
        return 0;
    }

    @Override
    public int productPointTransfer(Long fromUserId, String fromUsername, String toUsername, String toRealname,
                                    Integer amount) {
        amount = amount * 100;
        UserDO toUser = userDao.getByUsername(toUsername);
        ThrowUtils.throwCondition(toUser == null, 101, "转入用户不存在");
        ThrowUtils.throwCondition(!StringUtils.equals(toRealname, toUser.getName()), 102, "转入用户真实名错误");
        Integer productPointsTotal = this.productPointsTotal(fromUserId);
        ThrowUtils.throwCondition(productPointsTotal < amount, 103, "现金积分不足");

        //扣
        ProductPointsDO firstProductPointsDO = new ProductPointsDO();
        firstProductPointsDO.setAmount(-amount);
        firstProductPointsDO.setCreateTime(new Date());
        firstProductPointsDO.setLastModifyTime(new Date());
        firstProductPointsDO.setType(PointTradeType.TRANSFER); //TODO 类型
        firstProductPointsDO.setRemark("转出-去向用户【" + toRealname + "】");
        firstProductPointsDO.setUserId(fromUserId);
        firstProductPointsDO.setReciprocalUserId(toUser.getUserId());
        productPointsDOMapper.insertSelective(firstProductPointsDO);

        //收
        ProductPointsDO secondProductPointsDO = new ProductPointsDO();
        secondProductPointsDO.setAmount(amount);
        secondProductPointsDO.setCreateTime(new Date());
        secondProductPointsDO.setLastModifyTime(new Date());
        secondProductPointsDO.setType(PointTradeType.TRANSFER); //TODO 类型
        secondProductPointsDO.setRemark("转入-来源用户【" + fromUsername + "】");
        secondProductPointsDO.setUserId(toUser.getUserId());
        secondProductPointsDO.setReciprocalUserId(fromUserId);
        productPointsDOMapper.insertSelective(secondProductPointsDO);
        return 0;
    }

    /**
     * VIP会员分润，累计给予一年分红。
     * 分润总金额 = 公司出货量 * 定价 * 分润定价
     */
    @Override
    public void vipBonus() {
        //最后一次分红时间
        BonusFlag lastBonusFlag = pointsMapper.getLastBonusFlag(PointTradeType.VIP_BONUS);
        Date currentBonusTime = DateTime.now().toDate();
        Date lastBonusTime = currentBonusTime;
        lastBonusTime.setHours(0);
        lastBonusTime.setMinutes(0);
        if (lastBonusFlag != null) {
            lastBonusTime = lastBonusFlag.getLastActiveTime();
        }

        // 杜小栗商品定价
        long duXiaoLiPrice = distConfigValueService.getVIP_BOUND_DUXIAOLI_PRICE();

        // 黑莓商品定价
        long heiMeiPrice = distConfigValueService.getVIP_BOUND_HEIMEI_PRICE();

        // 任红比例
        double rate = distConfigValueService.getVIP_FEN_BONUS_RATE()/100.0;

        // 公司账号
        long companyAccountUserId = distConfigValueService.getCOMPANY_ACCOUNT_USER_ID();

        // 公司今日库存出货总数
        int duXiaoLiStocks = 0 - stockService.sumStocks(companyAccountUserId, ProductType.DU_XIAO_LI.getValue(),
                lastBonusTime,
                currentBonusTime);

        int heiMeiStocks = 0 - stockService.sumStocks(companyAccountUserId, ProductType.HEI_MEI.getValue(),
                lastBonusTime,
                currentBonusTime);

        long amount = 0L;
        if (duXiaoLiStocks > 0) {
            amount +=  duXiaoLiStocks * duXiaoLiPrice;
        }
        if (heiMeiStocks > 0) {
            amount +=  heiMeiStocks * heiMeiPrice;
        }
        if (amount == 0) {
            LOGGER.info("本次VIP分润没有新增业绩 起:{} 止:{}", lastBonusTime, currentBonusTime);
            return;
        } else {
            LOGGER.info("本次VIP分润新增业绩{}元, 起:{} 止:{}", amount/100.0,lastBonusTime, currentBonusTime);
        }
        //获取激活时间在一年内的VIP用户
        List<UserDO> vipUserList = userDao.getYearVipUser();
        if (vipUserList.isEmpty()) {
            LOGGER.info("VIP分红--一年内没有VIP用户");
        } else {
            //平均分红 5%
            Double avgAmount = (amount * rate) / vipUserList.size();
            //保存VIP分红
            for (UserDO user : vipUserList) {
                //分配现金积分
                CashPointsDO cashPointsDO = new CashPointsDO();
                Double cashAmount = avgAmount * 1;
                cashPointsDO.setAmount(cashAmount.intValue());
                cashPointsDO.setCreateTime(new Date());
                cashPointsDO.setLastModifyTime(new Date());
                cashPointsDO.setType(PointTradeType.VIP_BONUS);
                cashPointsDO.setRemark("VIP分红");
                cashPointsDO.setServiceCharge(0);
                cashPointsDO.setUserId(user.getUserId());
                cashPointsDOMapper.insertSelective(cashPointsDO);
            }
        }

        //保存当前分红的最后时间节点
        BonusFlag bonusFlag = new BonusFlag();
        bonusFlag.setType(PointTradeType.VIP_BONUS);
        bonusFlag.setLastActiveTime(currentBonusTime);
        pointsMapper.saveLastBonusFlag(bonusFlag);
    }

    @Override
    public void agentBonus() {
        LOGGER.info("=======   成为代理商可获得代理区域销售业绩的12%作为管理奖励   =========");
        List<UserDO> agentUserList = userDao.getAgentUserList(1);
        BonusFlag lastBonusFlag = pointsMapper.getLastBonusFlag(PointTradeType.AGENT_BONUS);
        Date lastBonusTime = DateTime.now().toDate();
        lastBonusTime.setHours(0);
        lastBonusTime.setMinutes(0);
        if (lastBonusFlag != null) {
            lastBonusTime = lastBonusFlag.getLastActiveTime();
        }
        //获取当前最后一个激活时间
        Date currentLastActiveTime = userDao.getUserLastActiveTime();
        if (agentUserList.isEmpty()) {
            LOGGER.info("没有代理--没有代理--没有代理");
        } else {
            for (UserDO user : agentUserList) {
                //1、该代理在没有其它代理情况下的总业绩 12%
                String lastBonusTimeStr = DateUtils.format(lastBonusTime, DateUtils.DATE_TIME_PATTERN);
                String currentLastActiveTimeStr = DateUtils.format(currentLastActiveTime, DateUtils.DATE_TIME_PATTERN);
                GroupInfo groupInfo = memberCache
                        .groupNewPerformance(user.getUserId(), lastBonusTimeStr, currentLastActiveTimeStr, 0, 1, 2, 3,
                                4, 5);
                //				LOGGER.info("userId : {} groupInfo : {} ",user.getUserId(),groupInfo);
                Double totalAmount = Double.valueOf(groupInfo.getAmount()) * 100;//精确到分
                if (totalAmount > 0) {
                    Double reate = getRate(user.getAgentLevel());
                    Double avgAmount = totalAmount * reate;
                    //管理团队奖
                    //分配现金积分
                    savePoints(avgAmount, user.getUserId(), PointTradeType.AGENT_BONUS, "代理团队奖" + reate.doubleValue());
                    //上两层拿收入的15% 领导管理奖
                    managerBonus(user.getUserId(), avgAmount);
                    //计算截流 团队奖
                    diffCash(user.getUserId(), user.getAgentLevel(), totalAmount);
                }
            }
        }
        //保存当前分红的最后时间节点
        BonusFlag bonusFlag = new BonusFlag();
        bonusFlag.setType(PointTradeType.AGENT_BONUS);
        bonusFlag.setLastActiveTime(currentLastActiveTime);
        pointsMapper.saveLastBonusFlag(bonusFlag);
    }

    @Override
    public void agent2Bonus() {
        LOGGER.info("=======   统计初级合伙人   =========");
        List<UserDO> agentUserList = userDao.getAgentUserList(2);
        BonusFlag lastBonusFlag = pointsMapper.getLastBonusFlag(PointTradeType.AGENT_2_BONUS);
        Date lastBonusTime = DateTime.now().toDate();
        lastBonusTime.setHours(0);
        lastBonusTime.setMinutes(0);
        if (lastBonusFlag != null) {
            lastBonusTime = lastBonusFlag.getLastActiveTime();
        }
        //获取当前最后一个激活时间
        Date currentLastActiveTime = userDao.getUserLastActiveTime();
        if (agentUserList.isEmpty()) {
            LOGGER.info("没有初级合伙人");
        } else {
            for (UserDO user : agentUserList) {
                //1、初级合伙人新增业绩有 5% + 15%的提成佣金
                String lastBonusTimeStr = DateUtils.format(lastBonusTime, DateUtils.DATE_TIME_PATTERN);
                String currentLastActiveTimeStr = DateUtils.format(currentLastActiveTime, DateUtils.DATE_TIME_PATTERN);
                GroupInfo groupInfo = memberCache
                        .groupNewPerformance(user.getUserId(), lastBonusTimeStr, currentLastActiveTimeStr, 0, 1, 2, 3,
                                4, 5);
                //				LOGGER.info("userId : {} groupInfo : {} ",user.getUserId(),groupInfo);
                Double totalAmount = Double.valueOf(groupInfo.getAmount()) * 100;//精确到分
                if (totalAmount > 0) {
                    Double reate = getRate(user.getAgentLevel());
                    Double avgAmount = totalAmount * reate;
                    //管理团队奖
                    //分配现金积分
                    savePoints(avgAmount, user.getUserId(), PointTradeType.AGENT_BONUS, "代理团队奖" + reate.doubleValue());
                    //上两层拿收入的15% 领导管理奖
                    managerBonus(user.getUserId(), avgAmount);
                    //计算截流 团队奖
                    diffCash(user.getUserId(), user.getAgentLevel(), totalAmount);
                }
            }
        }
        //保存当前分红的最后时间节点
        BonusFlag bonusFlag = new BonusFlag();
        bonusFlag.setType(PointTradeType.AGENT_2_BONUS);
        bonusFlag.setLastActiveTime(currentLastActiveTime);
        pointsMapper.saveLastBonusFlag(bonusFlag);

    }

    @Override
    public void agent3Bonus() {
        LOGGER.info("=======   统计中张合伙人  =========");
        List<UserDO> agentUserList = userDao.getAgentUserList(3);
        BonusFlag lastBonusFlag = pointsMapper.getLastBonusFlag(PointTradeType.AGENT_3_BONUS);
        Date lastBonusTime = DateTime.now().toDate();
        lastBonusTime.setHours(0);
        lastBonusTime.setMinutes(0);
        if (lastBonusFlag != null) {
            lastBonusTime = lastBonusFlag.getLastActiveTime();
        }
        //获取当前最后一个激活时间
        Date currentLastActiveTime = userDao.getUserLastActiveTime();
        if (agentUserList.isEmpty()) {
            LOGGER.info("没有中级合伙人");
        } else {
            for (UserDO user : agentUserList) {
                String lastBonusTimeStr = DateUtils.format(lastBonusTime, DateUtils.DATE_TIME_PATTERN);
                String currentLastActiveTimeStr = DateUtils.format(currentLastActiveTime, DateUtils.DATE_TIME_PATTERN);
                GroupInfo groupInfo = memberCache
                        .groupNewPerformance(user.getUserId(), lastBonusTimeStr, currentLastActiveTimeStr, 0, 1, 2, 3,
                                4, 5);
                //				LOGGER.info("userId : {} groupInfo : {} ",user.getUserId(),groupInfo);
                Double totalAmount = Double.valueOf(groupInfo.getAmount()) * 100;//精确到分
                if (totalAmount > 0) {
                    Double reate = getRate(user.getAgentLevel());
                    Double avgAmount = totalAmount * reate;
                    //管理团队奖
                    //分配现金积分
                    savePoints(avgAmount, user.getUserId(), PointTradeType.AGENT_BONUS, "代理团队奖" + reate.doubleValue());
                    //上两层拿收入的15% 领导管理奖
                    managerBonus(user.getUserId(), avgAmount);
                    //计算截流 团队奖
                    diffCash(user.getUserId(), user.getAgentLevel(), totalAmount);
                }
            }
        }
        //保存当前分红的最后时间节点
        BonusFlag bonusFlag = new BonusFlag();
        bonusFlag.setType(PointTradeType.AGENT_3_BONUS);
        bonusFlag.setLastActiveTime(currentLastActiveTime);
        pointsMapper.saveLastBonusFlag(bonusFlag);

    }

    @Override
    public void agent4Bonus() {
        LOGGER.info("=======   统计高级合伙人奖   =========");
        List<UserDO> agentUserList = userDao.getAgentUserList(4);
        BonusFlag lastBonusFlag = pointsMapper.getLastBonusFlag(PointTradeType.AGENT_4_BONUS);
        Date lastBonusTime = DateTime.now().toDate();
        lastBonusTime.setHours(0);
        lastBonusTime.setMinutes(0);
        if (lastBonusFlag != null) {
            lastBonusTime = lastBonusFlag.getLastActiveTime();
        }
        //获取当前最后一个激活时间
        Date currentLastActiveTime = userDao.getUserLastActiveTime();
        if (agentUserList.isEmpty()) {
            LOGGER.info("没有高级合伙人");
        } else {
            for (UserDO user : agentUserList) {
                //1、高级合伙人新增业绩有 5% + 25%的提成佣金
                String lastBonusTimeStr = DateUtils.format(lastBonusTime, DateUtils.DATE_TIME_PATTERN);
                String currentLastActiveTimeStr = DateUtils.format(currentLastActiveTime, DateUtils.DATE_TIME_PATTERN);
                GroupInfo groupInfo = memberCache
                        .groupNewPerformance(user.getUserId(), lastBonusTimeStr, currentLastActiveTimeStr, 0, 1, 2, 3,
                                4, 5);
                //				LOGGER.info("userId : {} groupInfo : {} ",user.getUserId(),groupInfo);
                Double totalAmount = Double.valueOf(groupInfo.getAmount()) * 100;//精确到分
                if (totalAmount > 0) {
                    Double reate = getRate(user.getAgentLevel());
                    Double avgAmount = totalAmount * reate;
                    //管理团队奖
                    //分配现金积分
                    savePoints(avgAmount, user.getUserId(), PointTradeType.AGENT_BONUS, "代理团队奖" + reate.doubleValue());
                    //上两层拿收入的15% 领导管理奖
                    managerBonus(user.getUserId(), avgAmount);
                    //计算截流 团队奖
                    diffCash(user.getUserId(), user.getAgentLevel(), totalAmount);

                }
            }
        }
        //保存当前分红的最后时间节点
        BonusFlag bonusFlag = new BonusFlag();
        bonusFlag.setType(PointTradeType.AGENT_4_BONUS);
        bonusFlag.setLastActiveTime(currentLastActiveTime);
        pointsMapper.saveLastBonusFlag(bonusFlag);

    }

    @Override
    public void agent5Bonus() {
        LOGGER.info("=======   统计联合创始人   =========");
        List<UserDO> agentUserList = userDao.getAgentUserList(5);
        BonusFlag lastBonusFlag = pointsMapper.getLastBonusFlag(PointTradeType.AGENT_5_BONUS);
        Date lastBonusTime = DateTime.now().toDate();
        lastBonusTime.setHours(0);
        lastBonusTime.setMinutes(0);
        if (lastBonusFlag != null) {
            lastBonusTime = lastBonusFlag.getLastActiveTime();
        }
        //获取当前最后一个激活时间
        Date currentLastActiveTime = userDao.getUserLastActiveTime();
        if (agentUserList.isEmpty()) {
            LOGGER.info("没有");
        } else {
            for (UserDO user : agentUserList) {
                //1、联合创始人新增业绩有 5% + 28%的提成佣金
                String lastBonusTimeStr = DateUtils.format(lastBonusTime, DateUtils.DATE_TIME_PATTERN);
                String currentLastActiveTimeStr = DateUtils.format(currentLastActiveTime, DateUtils.DATE_TIME_PATTERN);
                GroupInfo groupInfo = memberCache
                        .groupNewPerformance(user.getUserId(), lastBonusTimeStr, currentLastActiveTimeStr, 0, 1, 2, 3,
                                4, 5);
                //				LOGGER.info("userId : {} groupInfo : {} ",user.getUserId(),groupInfo);
                Double totalAmount = Double.valueOf(groupInfo.getAmount()) * 100;//精确到分
                if (totalAmount > 0) {
                    Double reate = getRate(user.getAgentLevel());
                    Double avgAmount = totalAmount * reate;
                    //管理团队奖
                    //分配现金积分
                    savePoints(avgAmount, user.getUserId(), PointTradeType.AGENT_BONUS, "代理团队奖" + reate.doubleValue());
                    //上两层拿收入的15% 领导管理奖
                    managerBonus(user.getUserId(), avgAmount);
                }
            }
        }
        //保存当前分红的最后时间节点
        BonusFlag bonusFlag = new BonusFlag();
        bonusFlag.setType(PointTradeType.AGENT_5_BONUS);
        bonusFlag.setLastActiveTime(currentLastActiveTime);
        pointsMapper.saveLastBonusFlag(bonusFlag);

    }

    private void savePoints(Double amount, Long userId, Integer type, String remark) {
        CashPointsDO aaatCashPointsDO = new CashPointsDO();
        Double aaaca = amount * 0.6;
        aaatCashPointsDO.setAmount(aaaca.intValue());
        aaatCashPointsDO.setCreateTime(new Date());
        aaatCashPointsDO.setLastModifyTime(new Date());
        aaatCashPointsDO.setType(type);
        aaatCashPointsDO.setRemark(remark);
        aaatCashPointsDO.setServiceCharge(0);//TODO 手续费,只有提现的时候有手续费
        aaatCashPointsDO.setUserId(userId);
        cashPointsDOMapper.insertSelective(aaatCashPointsDO);
        //分配商品积分
        ProductPointsDO aaaProductPointsDO = new ProductPointsDO();
        Double aaapa = amount * 0.4;
        aaaProductPointsDO.setAmount(aaapa.intValue());
        aaaProductPointsDO.setCreateTime(new Date());
        aaaProductPointsDO.setLastModifyTime(new Date());
        aaaProductPointsDO.setType(type);
        aaaProductPointsDO.setRemark(remark);
        aaaProductPointsDO.setUserId(userId);
        productPointsDOMapper.insertSelective(aaaProductPointsDO);
    }

    private void managerBonus(Long userId, Double amount) {
        //上一层拿收入的15%
        List<NodeVO> mmNodeVOList = memberCache.findGroupParent(userId, 1,
                info -> info != null && info.getAgentLevel() != null && info.getAgentLevel() >= 1);
        if (null != mmNodeVOList && !mmNodeVOList.isEmpty()) {
            //			LOGGER.info("mmNodeVOList : {}",JSON.toJSONString(mmNodeVOList));
            //上两层代理拿 15%管理奖金
            Double aaaAmount = amount * 0.15d;
            NodeVO managementNodeVO = mmNodeVOList.get(0);
            Long managementUserId = managementNodeVO.getUserId();
            savePoints(aaaAmount, managementUserId, PointTradeType.MANAGE_AGENT_BONUS, "管理领导奖15%");
        }
        //还可获得间接代理总奖金的15%
        List<NodeVO> mmmNodeVOList = memberCache.findGroupParent(userId, 2,
                info -> info != null && info.getAgentLevel() != null && info.getAgentLevel() >= 1);
        if (null != mmmNodeVOList && !mmmNodeVOList.isEmpty() && mmmNodeVOList.size() == 2) {
            //			LOGGER.info("mmmNodeVOList : {}",JSON.toJSONString(mmmNodeVOList));
            //上两层代理拿 15%管理奖金
            Double aaaAmount = amount * 0.15d;
            NodeVO managementNodeVO = mmmNodeVOList.get(1);
            Long managementUserId = managementNodeVO.getUserId();
            savePoints(aaaAmount, managementUserId, PointTradeType.MANAGE_AGENT_BONUS, "管理领导奖15%");
        }
    }

    private Double diffRate(Integer agent1Level, Integer agent2Level) {
        Double agent1Rate = getRate(agent1Level);
        Double agent2Rate = getRate(agent2Level);
        BigDecimal d1 = new BigDecimal(Double.toString(agent1Rate));
        BigDecimal d2 = new BigDecimal(Double.toString(agent2Rate));
        return d2.subtract(d1).doubleValue();
    }

    public Double getRate(Integer agentLevel) {
        Double agentRate = 0d;
        switch (agentLevel) {
            case 1:
                agentRate = 0.12d;
                break;
            case 2:
                agentRate = 0.20d;
                break;
            case 3:
                agentRate = 0.25d;
                break;
            case 4:
                agentRate = 0.30d;
                break;
            case 5:
                agentRate = 0.35d;
                break;
            default:
                break;
        }
        return agentRate;
    }

    private NodeVO diffCash(Long userId, Integer agentLevel, Double totalAmount) {
        List<NodeVO> agentNodeVOList = memberCache.findGroupParent(userId, 1,
                info -> info != null && info.getAgentLevel() != null && info.getAgentLevel() > agentLevel);
        NodeVO managementNodeVO = null;
        if (null != agentNodeVOList && !agentNodeVOList.isEmpty()) {
            //			LOGGER.info("agentNodeVOList : {}",JSON.toJSONString(agentNodeVOList));
            //上一层初级初级合伙人拿提成
            managementNodeVO = agentNodeVOList.get(0);
            NodeInfo userNodeInfo = memberCache.getNodeInfo(userId);
            Double agent2Rate = diffRate(userNodeInfo.getAgentLevel(), managementNodeVO.getAgentLevel());
            Double aaaAmount = totalAmount * agent2Rate;
            //分配现金积分
            savePoints(aaaAmount, managementNodeVO.getUserId(), PointTradeType.AGENT_BONUS,
                    "管理领导奖" + agent2Rate.doubleValue());
            //上两层拿收入的15% 领导管理奖
            managerBonus(managementNodeVO.getUserId(), aaaAmount);
            if (managementNodeVO.getAgentLevel() < 5) {
                diffCash(managementNodeVO.getUserId(), managementNodeVO.getAgentLevel(), totalAmount);
            }
        }
        return managementNodeVO;
    }

    private Long bonus(Long userId, Integer findCount, Predicate<NodeInfo> predicate, Double amount, Double rate,
                       Integer type) {
        List<NodeVO> agent5NodeVOList = memberCache.findGroupParent(userId, findCount, predicate);
        Long managementUserId = null;
        if (null != agent5NodeVOList && !agent5NodeVOList.isEmpty()) {
            //			LOGGER.info("agent5NodeVOList : {}",JSON.toJSONString(agent5NodeVOList));
            //上一层初级合伙人拿3%提成
            Double aaaAmount = amount * rate;
            NodeVO managementNodeVO = agent5NodeVOList.get(0);
            managementUserId = managementNodeVO.getUserId();
            savePoints(aaaAmount, managementUserId, type, "管理领导奖" + rate.doubleValue());
        }
        return managementUserId;
    }

    @Override
    public List<Integer> reportIncome(String startDate, String endDate) {
        List<Integer> data = new ArrayList<>();
        int diffDay = 10;
        if (null != startDate && null != endDate) {
            diffDay = DateUtils.daysOfTwo(DateUtils.StrToDate(endDate, DateUtils.DATE_PATTERN),
                    DateUtils.StrToDate(startDate, DateUtils.DATE_PATTERN));
        } else {
            Date now = DateTime.now().toDate();
            endDate = DateUtils.format(now, DateUtils.DATE_PATTERN);
            Date daysAgo = DateTime.now().minusDays(diffDay - 1).toDate();
            startDate = DateUtils.format(daysAgo, DateUtils.DATE_PATTERN);
        }
        LOGGER.info("startDate : {} endDate : {}", startDate, endDate);
        for (int i = 0; i < diffDay; i++) {
            data.add(0);
        }
        Date now = DateTime.now().toDate();
        LOGGER.info("startDate : {} endDate : {}", startDate, endDate);
        List<UserDO> userList = userDao.achievement(startDate, endDate);
        if (null != userList && !userList.isEmpty()) {
            for (UserDO userDO : userList) {
                int diff = DateUtils.daysOfTwo(now, userDO.getActiveTime());
                int idx = ((diffDay - 1) - diff) % diffDay;
                int amount = 0;
                if (userDO.getMemberLevel() == 1) {
                    amount = 1100;
                } else if (userDO.getMemberLevel() == 2) {
                    amount = 3300;
                } else if (userDO.getMemberLevel() == 3) {
                    amount = 9900;
                }
                //				LOGGER.info("now : {},activeTime : {} diff : {} ,idx : {} ",DateUtils.format(now,
                // DateUtils.DATE_PATTERN),DateUtils.format(userDO.getActiveTime(), DateUtils.DATE_PATTERN),diff,idx);
                data.set(idx, data.get(idx) + amount);
            }
        }
        return data;
    }

    @Override
    public List<Integer> reportExpend(String startDate, String endDate) {
        List<Integer> data = new ArrayList<>();
        int diffDay = 10;
        if (null != startDate && null != endDate) {
            diffDay = DateUtils.daysOfTwo(DateUtils.StrToDate(endDate, DateUtils.DATE_PATTERN),
                    DateUtils.StrToDate(startDate, DateUtils.DATE_PATTERN));
        } else {
            Date now = DateTime.now().toDate();
            endDate = DateUtils.format(now, DateUtils.DATE_PATTERN);
            Date daysAgo = DateTime.now().minusDays(diffDay - 1).toDate();
            startDate = DateUtils.format(daysAgo, DateUtils.DATE_PATTERN);
        }
        LOGGER.info("startDate : {} endDate : {}", startDate, endDate);
        for (int i = 0; i < diffDay; i++) {
            data.add(0);
        }
        Date now = DateTime.now().toDate();
        LOGGER.info("startDate : {} endDate : {}", startDate, endDate);
        List<CashPointsDO> cashPointsList = pointsMapper.reportExpend(startDate, endDate);
        if (null != cashPointsList && !cashPointsList.isEmpty()) {
            for (CashPointsDO cashPoints : cashPointsList) {
                int diff = DateUtils.daysOfTwo(now, cashPoints.getCreateTime());
                int idx = ((diffDay - 1) - diff) % diffDay;
                int amount = cashPoints.getAmount();
                data.set(idx, data.get(idx) + amount);
            }
        }
        for (int i = 0; i < data.size(); i++) {
            data.set(i, data.get(i) / 100);
        }
        return data;
    }

    @Override
    public List<Integer> reportIncomeMonth(String startDate, String endDate) {
        List<Integer> data = new ArrayList<>();
        int diffDay = 12;
        if (null != startDate && null != endDate) {
            diffDay = DateUtils.daysOfTwoMonth(DateUtils.StrToDate(endDate, DateUtils.MONTH_PATTERN),
                    DateUtils.StrToDate(startDate, DateUtils.MONTH_PATTERN));
        } else {
            Date now = DateTime.now().toDate();
            now = DateUtils.getLastDayOfMonth(now);
            endDate = DateUtils.format(now, DateUtils.DATE_PATTERN);
            Date daysAgo = DateTime.now().minusMonths(diffDay - 1).toDate();
            startDate = DateUtils.format(daysAgo, DateUtils.MONTH_PATTERN);
        }
        ;
        LOGGER.info("startDate : {} endDate : {}", startDate.concat("-00"), endDate);
        for (int i = 0; i < diffDay; i++) {
            data.add(0);
        }
        Date now = DateTime.now().toDate();
        now = DateUtils.getLastDayOfMonth(now);
        List<UserDO> userList = userDao.achievement(startDate.concat("-01"), endDate);
        if (null != userList && !userList.isEmpty()) {
            for (UserDO userDO : userList) {
                int diff = DateUtils.daysOfTwoMonth(now, userDO.getActiveTime());
                int idx = ((diffDay - 1) - diff) % diffDay;
                int amount = 0;
                if (userDO.getMemberLevel() == 1) {
                    amount = 1100;
                } else if (userDO.getMemberLevel() == 2) {
                    amount = 3300;
                } else if (userDO.getMemberLevel() == 3) {
                    amount = 9900;
                }
                LOGGER.info("now : {},activeTime : {} diff : {} ,idx : {} ",
                        DateUtils.format(now, DateUtils.MONTH_PATTERN),
                        DateUtils.format(userDO.getActiveTime(), DateUtils.MONTH_PATTERN), diff, idx);
                data.set(idx, data.get(idx) + amount);
            }
        }
        return data;
    }

    @Override
    public List<Integer> reportExpendMonth(String startDate, String endDate) {
        List<Integer> data = new ArrayList<>(100000);
        int diffDay = 12;
        if (null != startDate && null != endDate) {
            diffDay = DateUtils.daysOfTwoMonth(DateUtils.StrToDate(endDate, DateUtils.MONTH_PATTERN),
                    DateUtils.StrToDate(startDate, DateUtils.MONTH_PATTERN));
        } else {
            Date now = DateTime.now().toDate();
            now = DateUtils.getLastDayOfMonth(now);
            endDate = DateUtils.format(now, DateUtils.DATE_PATTERN);
            Date daysAgo = DateTime.now().minusMonths(diffDay - 1).toDate();
            startDate = DateUtils.format(daysAgo, DateUtils.MONTH_PATTERN);
        }
        LOGGER.info("startDate : {} endDate : {}", startDate, endDate);
        for (int i = 0; i < diffDay; i++) {
            data.add(0);
        }
        Date now = DateTime.now().toDate();
        now = DateUtils.getLastDayOfMonth(now);
        LOGGER.info("startDate : {} endDate : {}", startDate, endDate);
        List<CashPointsDO> cashPointsList = pointsMapper.reportExpend(startDate.concat("-01"), endDate);
        if (null != cashPointsList && !cashPointsList.isEmpty()) {
            for (CashPointsDO cashPoints : cashPointsList) {
                int diff = DateUtils.daysOfTwoMonth(now, cashPoints.getCreateTime());
                int idx = ((diffDay - 1) - diff) % diffDay;
                int amount = cashPoints.getAmount();
                data.set(idx, data.get(idx) + amount);
            }
        }
        for (int i = 0; i < data.size(); i++) {
            data.set(i, data.get(i) / 100);
        }
        return data;
    }

    @Override
    public Map<String, Double> amountSum() {
        Map<String, Double> data = new HashMap();
        Integer a1 = pointsMapper.availableAmount();
        Integer a2 = pointsMapper.alreadyPresentedAmount();
        BigDecimal d1 = new BigDecimal(Double.toString(a1));
        BigDecimal d2 = new BigDecimal(Double.toString(a2));
        BigDecimal r1 = d1.divide(new BigDecimal("100"));
        BigDecimal r2 = d2.divide(new BigDecimal("100"));
        data.put("r1", r1.doubleValue());
        data.put("r2", r2.doubleValue());
        return data;
    }
}
